#include "../header.h"
//udp接收端编程。只接收数据。但是也可增加发送功能。
//1 socket : 建立数据报套接字
//2.bind 绑定  绑定自己的IP PORT  sid
//3.接收数据， recvfrom
//4.关闭套接字。
/**
 * @函数原型: ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
 *              struct sockaddr *src_addr, socklen_t *addrlen);
 * @函数功能: receive a message from a socket  从套接字文件中。接收数据。
 * @参数说明: 
 * @       参数1: sockfd  套接字
 * @       参数2: buf 接收数据缓冲区的起始位置。
 * @       参数3: len ：缓冲区长度。
 *  @       参数4: flags ： 0 。
 *  @       参数5: struct sockaddr *src_addr ： 地质结构体，存储对方的信息，对方是发送端。
 *  @       参数6: addrlen ： 地址长度的地址。
 * @返回值: These calls return the number of bytes received, or -1 if an error occurred.
 * 实际读到的字节个数。
 * @param {int} argc
 */
//接收端  ./a.out + 自己的ip + port ； 
int main(int argc, char const *argv[])
{
    //从命令行把ip port传递进来。
    if(argc < 3)
    {
        perror("命令行正确参数:./a.out ip port\n");
        return -1;
    }

    int sid = socket(AF_INET,SOCK_DGRAM,0);
    printf("sid = %d\n",sid);

    //2 bind
    struct sockaddr_in saddr = {0};
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    saddr.sin_port = htons(atoi(argv[2]));
    saddr.sin_family = AF_INET;
    int res = bind(sid,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res < 0)
    {
        perror("绑定失败!\n");
        return -2;
    }
    printf("绑定成功!\n");

    //3.接收数据信息。
    //caddr： 存储对方的地址信息。
    struct sockaddr_in caddr = {0};
    char bufs[128] = "";
    int size = sizeof(caddr);
    //recv read recvfrom 都是阻塞属性
    //循环接收数据。
    int len = 0 ;
    char ipk[16] = "";

    char bufk[128] = "";
    //先接收 - 再发送
    //目标是 任意发送任意接收。

    //------------------POLL准备工作---------------------------//
    struct pollfd pfds[2] = {0};
    pfds[0].fd = STDIN_FILENO;
    pfds[0].events = POLLIN;
    
    //sid
    pfds[1].fd = sid;
    pfds[1].events = POLLIN;

    //文件描述符的 响应个数一个是 缓冲区。
    int count = 0 ; 
    char buff[128] = "";
    //---------------------------------------------//
    while(1)
    {

        count = poll(pfds,2,3000);
        if(count == 0 )
            printf("没有文件描述符准备好了! count = %d\n",count);

        //sid的输入事件
        if(pfds[1].revents == POLLIN)
        {
            bzero(bufs,sizeof(bufs));
            bzero(ipk,sizeof(ipk));//清空数组
            len = recvfrom(sid,bufs,sizeof(bufs),0,(struct sockaddr*)&caddr,&size);
            printf("发送端的ip是:%s\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ipk,sizeof(ipk)));
            printf("发送端的端口号是:%d\n",ntohs(caddr.sin_port));
            printf("发送端的信息是:%s 数据长度是:%d\n",bufs,len);
            if(!strncmp(bufs,"quit",4))  
            {
                printf("接收端正在退出...\n");
            }
            count = 0 ; 
        }
        //键盘事件
        if(pfds[0].revents == POLLIN)
        {
            //从键盘接收数据 发送对面
            bzero(bufk,sizeof(bufk));
            fgets(bufk,sizeof(bufk),stdin);
            len = sendto(sid,bufk,strlen(bufk),0,(struct sockaddr*)&caddr,sizeof(caddr));
            printf("数据已经发送，发送给发送端的数据长度是:%d\n",len);
            count = 0 ; 
        }
    }
    //关闭套接字
    close(sid);
    return 0;
}
